package com.xhwl.centiotdata.handler.visitor.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.xhwl.centiotdata.handler.visitor.VisitorIntegrationFactory;
import com.xhwl.centiotdata.handler.visitor.VisitorIntegrationHandler;
import com.xhwl.centiotdata.pojo.constant.MiLiConstant;
import com.xhwl.centiotdata.pojo.dto.mili.TenementMiLiDTO;
import com.xhwl.centiotdata.pojo.dto.mili.WorkerMiLiDTO;
import com.xhwl.centiotdata.pojo.dto.pedestrian.PedestrianIntegrationConfigDTO;
import com.xhwl.centiotdata.pojo.dto.visitor.VisitorIntegrationConfigDTO;
import com.xhwl.centiotdata.service.cent.IAccountCentService;
import com.xhwl.centiotdata.service.cent.IAuthAccountCentService;
import com.xhwl.centiotdata.service.cent.IOrganizationService;
import com.xhwl.centiotdata.service.cent.IResidentInfoService;
import com.xhwl.centiotdata.suppliersystem.mili.PedestrianMiLiHandler;
import com.xhwl.centiotdata.suppliersystem.mili.VisitorMiLiHandler;
import com.xhwl.centiotdata.utils.Base64Utils;
import com.xhwl.centiotdata.utils.RedisUtils;
import com.xhwl.common.dto.cent.visitor.VisitorAuthDTO;
import com.xhwl.common.dto.cent.visitor.VisitorInfoDTO;
import com.xhwl.common.enums.ProductEnum;
import com.xhwl.common.exception.BusinessException;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.auth.AuthAccountMapping;
import com.xhwl.common.pojo.cent.sdata.Account;
import com.xhwl.common.pojo.cent.sdata.Organization;
import com.xhwl.common.pojo.cent.sdata.Room;
import com.xhwl.common.pojo.cent.visitor.Follower;
import com.xhwl.common.query.cent.sdata.RoomQuery;
import com.xhwl.common.utils.ChkUtil;
import com.xhwl.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: wuyuhao
 * @createDate: 2022/10/26 18:59
 */
@Slf4j
@Service
public class VisitorIntegrationMiLiHandler extends VisitorIntegrationHandler {

    @Resource
    private VisitorMiLiHandler visitorMiLiHandler;

    @Autowired
    private IAuthAccountCentService authAccountCentService;

    @Resource
    private IAccountCentService iAccountCentService;

    @Autowired
    private IResidentInfoService iResidentInfoService;

    @Autowired
    private PedestrianMiLiHandler pedestrianMiLiHandler;

    @Resource
    private IAuthAccountCentService iAuthPedestrianCentService;

    @Autowired
    private IOrganizationService iOrganizationService;

    @Autowired
    private RedisUtils redisUtils;


    @Override
    public void afterPropertiesSet() throws Exception {
        // 米立人行
        VisitorIntegrationFactory.register(ProductEnum.MILI_PEDESTRIAN.getId(), this);
    }

    @Override
    public ResultJson createVisitorAuth(VisitorIntegrationConfigDTO configDTO, VisitorAuthDTO authDTO) {
        log.info("创建访客信息:{}", JSONObject.toJSONString(authDTO));
        AuthAccountMapping accountMapping = authAccountCentService.query(configDTO.getProjectId(), authDTO.getIntervieweeId(), configDTO.getProductId());
        if(accountMapping != null) {
            log.info("accountMapping: {}", JSONObject.toJSONString(accountMapping));
            List<String> openIds = Arrays.asList(accountMapping.getOpenId().split(","));
            List<String> frameNoAndOpenId = Arrays.asList(openIds.get(0).split("_"));
            String openId = frameNoAndOpenId.get(1);

            List<Follower> followerList = authDTO.getFollowerList();
            Map<String, Object> map = new HashMap<>();
            map.put("VIName", authDTO.getName());
            map.put("VISex", 1);
            map.put("VICredentialType", "111");
            map.put("VICredentialID", authDTO.getIdentityCard());
            map.put("VIPersonNumber", 1 + followerList.size());
            map.put("VIDestID", openId);
            map.put("VIVisitorTime", DateUtil.formatDateTime(authDTO.getAuthStartTime()));
            map.put("VILeaveTime", DateUtil.formatDateTime(authDTO.getAuthEndTime()));
            if(ChkUtil.isNotNull(authDTO.getFaceUrl())) {
                map.put("VIImageInBase64", Base64Utils.getBaseByUrl(authDTO.getFaceUrl()));
            }
            visitorMiLiHandler.visitorAdd(configDTO, map);
        }

        return ResultJson.success();
    }

    @Override
    public ResultJson removeVisitorAuth(VisitorIntegrationConfigDTO configDTO, VisitorInfoDTO infoDTO) {
        return ResultJson.success();
    }

    @Override
    public ResultJson getQrCode(VisitorIntegrationConfigDTO configDTO, VisitorAuthDTO visitorAuthDTO) {
        Object qrCode = redisUtils.get(String.format(MiLiConstant.VISITOR_QRCODE_KEY, visitorAuthDTO.getId()));
        if(qrCode != null) {
            return ResultJson.success(qrCode);
        }
        // 查询是否已同步人员
        AuthAccountMapping authAccountMapping = authAccountCentService.query(visitorAuthDTO.getProjectId(),visitorAuthDTO.getIntervieweeId(), visitorAuthDTO.getProductId());
        String openId;
        if(authAccountMapping != null) {
            openId = authAccountMapping.getOpenId();
        } else {
            // 同步人员
            openId = this.add(visitorAuthDTO.getIntervieweeId(), configDTO);
        }
        visitorAuthDTO.setIntervieweeOpenId(openId);
        return visitorMiLiHandler.getQrCode(configDTO, visitorAuthDTO);
    }


    private String add(Integer accountId, VisitorIntegrationConfigDTO config) {
        log.info("accountId: {}  , config: {}", accountId, config);
        try {
            PedestrianIntegrationConfigDTO configDTO = new PedestrianIntegrationConfigDTO();
            BeanUtils.copyProperties(config, configDTO);
            configDTO.setProductId(config.getProductId());
            configDTO.setProjectId(config.getProjectId());

            Account account = iAccountCentService.findById(accountId);
            List<Organization> organizationList = iResidentInfoService.getOrgListByAccountId(String.valueOf(accountId), config.getProjectId());
            long id;
            List<String> openIdList = new ArrayList<>();
            if (ObjectUtils.isEmpty(organizationList)) {
                WorkerMiLiDTO workerMiLiDTO = this.handleWorkerInfo(account);
                log.info("workerMiLiDTO: {}", workerMiLiDTO);
                WorkerMiLiDTO addWorker = pedestrianMiLiHandler.addWorker(configDTO, workerMiLiDTO);
                if (ObjectUtils.isEmpty(addWorker)) {
                    throw new BusinessException("添加米立工作人员失败！");
                } else {
                    id = addWorker.getGuardID();
                    // 工作人员添加人脸
                    if (StringUtils.isNotEmpty(account.getFaceUrl())) {
                        Map<String, Object> map = new HashMap<>();
                        map.put("ID", id);
                        // 1：住户（默认）；2：工作人员
                        map.put("PersonType", 2);
                        map.put("Photo", "data:image/jpeg;base64," + Base64Utils.imageUrlToBase64(account.getFaceUrl()));
                        pedestrianMiLiHandler.addFace(configDTO, map);
                    }
                }
            } else {
                List<Integer> orgIdList = organizationList.stream().map(Organization::getId).collect(Collectors.toList());
                RoomQuery roomQuery = new RoomQuery();
                roomQuery.setOrgIds(orgIdList);
                roomQuery.setProjectId(configDTO.getProjectId());
                List<Room> roomList = iOrganizationService.list(roomQuery);
                for(Room room : roomList) {
                    TenementMiLiDTO tenementMiLiDTO = this.handleResidentInfo(account, room);
                    Map<String, Object> map = new HashMap<>();
                    map.put("FrameNo", tenementMiLiDTO.getFrameNo());
                    List<TenementMiLiDTO> tenementMiLiDTOList = pedestrianMiLiHandler.queryTenement(configDTO, map);
                    // 当该房间下面有用户，表示已经有业主了，需要手动指定其与业主的关系
                    if (!tenementMiLiDTOList.isEmpty()) {
                        tenementMiLiDTO.setRelationshipDesc("其他");
                    }
                    log.info("tenementMiLiDTO: {}", tenementMiLiDTO);
                    TenementMiLiDTO addTenement = pedestrianMiLiHandler.addTenement(configDTO, tenementMiLiDTO);
                    if (ObjectUtils.isEmpty(addTenement)) {
                        throw new BusinessException("添加米立住户失败！");
                    } else {
                        id = addTenement.getID();
                        // 用房间号拼接上住户id，例如 02011703_1
                        openIdList.add(addTenement.getFrameNo() + "_" + id);
                        // 住户添加人脸
                        if (StringUtils.isNotEmpty(account.getFaceUrl())) {
                            map.clear();
                            map.put("ID", id);
                            // 1：住户（默认）；2：工作人员
                            map.put("PersonType", 1);
                            map.put("Photo", "data:image/jpeg;base64," + Base64Utils.imageUrlToBase64(account.getFaceUrl()));
                            pedestrianMiLiHandler.addFace(configDTO, map);
                        }
                    }
                }
            }
            // 中台这边一个住户，对应米立可能有多个住户id，在米立平台，一个住户只能绑定一个房屋，如果有多个房屋，需要新增多个住户去绑定。工作人员不会有这种情况
            // 比如01房有个张三，02房也有个张三，虽然是同一个人，但是他们id是不一样的，所以第三方id使用：房间号 + "_" + id，然后用逗号拼接成一个字符串，如："01010101_1,02010101_2"
            String openId = String.join(",", openIdList);
            //保存人员id关联表
            boolean saveAuthResult = iAuthPedestrianCentService.save(config.getProjectId(), accountId,
                    openId, null, config.getProductId());
            log.info("米立账号关联关系保存结果 : {}", saveAuthResult);
            return openId;
        } catch (Exception e) {
            log.error("配置信息：{}", config);
            log.error("同步米立平台异常", e);
            throw new BusinessException();
        }
    }

    private WorkerMiLiDTO handleWorkerInfo(Account account) {
        WorkerMiLiDTO workerMiLiDTO = new WorkerMiLiDTO();
        workerMiLiDTO.setGuardID(-1);
        if (!ObjectUtils.isEmpty(account.getName())) {
            workerMiLiDTO.setName(account.getName());
        } else {
            workerMiLiDTO.setName("工作人员");
        }
        if (!ObjectUtils.isEmpty(account.getPhone())) {
            workerMiLiDTO.setTelephone(account.getPhone());
        } else {
            throw new BusinessException("没有电话号码！");
        }
        if (!ObjectUtils.isEmpty(account.getSex())) {
            if (account.getSex() == 0) {
                workerMiLiDTO.setGender("2");
            } else if (account.getSex() == 1) {
                workerMiLiDTO.setGender("1");
            } else {
                workerMiLiDTO.setGender("0");
            }
        } else {
            workerMiLiDTO.setGender("0");
        }
        workerMiLiDTO.setCredentialType("111");
        return workerMiLiDTO;
    }

    private TenementMiLiDTO handleResidentInfo(Account account, Room room) {
        TenementMiLiDTO tenementMiLiDTO = new TenementMiLiDTO();
        // 中台创建房间时，需手动填写编码，保持与米立平台房间框架编码一致
        String frameNO = room.getCode();
        if (ObjectUtils.isEmpty(frameNO)) {
            throw new BusinessException("米立该框架不存在！");
        } else {
            tenementMiLiDTO.setFrameNo(frameNO);
        }

        tenementMiLiDTO.setID(-1);
        if (!ObjectUtils.isEmpty(account.getName())) {
            tenementMiLiDTO.setName(account.getName());
        } else {
            tenementMiLiDTO.setName(frameNO);
        }
        if (!ObjectUtils.isEmpty(account.getPhone())) {
            tenementMiLiDTO.setTelephone(account.getPhone());
            tenementMiLiDTO.setTelephone2(account.getPhone());
        } else {
            throw new BusinessException("没有电话号码！");
        }
        if (!ObjectUtils.isEmpty(account.getSex())) {
            if (account.getSex() == 0) {
                tenementMiLiDTO.setGender("2");
            } else if (account.getSex() == 1) {
                tenementMiLiDTO.setGender("1");
            } else {
                tenementMiLiDTO.setGender("0");
            }
        } else {
            tenementMiLiDTO.setGender("0");
        }
        tenementMiLiDTO.setCredentialType("111");
        return tenementMiLiDTO;
    }
}
